using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Password = Be.Timvw.Framework.Security.HmacOneTimePassword;

namespace Be.Timvw.Framework.Tests.Security.HmacOneTimePassword
{
    /// <summary>
    /// Tests for HmacOneTimePassword
    /// <see cref="http://tools.ietf.org/html/rfc4226#appendix-D"/>
    /// </summary>
    [TestClass]
    public class HmacOneTimePasswordTester
    {
        private const string Secret = "12345678901234567890";

        private readonly string[] expectedHashesInHex = new string[]
        {
            "cc93cf18508d94934c64b65d8ba7667fb7cde4b0", 
            "75a48a19d4cbe100644e8ac1397eea747a2d33ab", 
            "0bacb7fa082fef30782211938bc1c5e70416ff44",
            "66c28227d03a2d5529262ff016a1e6ef76557ece",
            "a904c900a64b35909874b33e61c5938a8e15ed1c",
            "a37e783d7b7233c083d4f62926c7a25f238d0316",
            "bc9cd28561042c83f219324d3c607256c03272ae", 
            "a4fb960c0bc06e1eabb804e5b397cdc4b45596fa", 
            "1b3c89f65e6c9e883012052823443f048b4332db",
            "1637409809a679dc698207310c8c7fc07290d9e5"
        };

        private readonly string[] expectedHmacOneTimePasswords = new string[]
        {
            "755224", 
            "287082", 
            "359152", 
            "969429", 
            "338314",
            "254676", 
            "287922", 
            "162583", 
            "399871", 
            "520489"
        };

        private Password HmacOneTimePassword
        {
            get { return new Password(Secret); }
        }

        private string HashToHex(byte[] hash)
        {
            return BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
        }

        [TestMethod]
        public void GetHashShouldReturnHashesAsInRfc()
        {
            Password hmacOneTimePassword = this.HmacOneTimePassword;
            for(int iterationNumber = 0; iterationNumber < this.expectedHashesInHex.Length; ++iterationNumber)
            {
                string expected = this.expectedHashesInHex[iterationNumber];

                byte[] generatedHash = hmacOneTimePassword.GetHash(iterationNumber);
                string actual = this.HashToHex(generatedHash);

                Assert.AreEqual(expected, actual);
            }
        }

        [TestMethod]
        public void GetPasswordShouldReturnPasswordsAsInRfc()
        {
            Password hmacOneTimePassword = this.HmacOneTimePassword;
            for(int iterationNumber = 0; iterationNumber < this.expectedHashesInHex.Length; ++iterationNumber)
            {
                string expected = this.expectedHmacOneTimePasswords[iterationNumber];
                string actual = hmacOneTimePassword.GetPassword(iterationNumber);

                Assert.AreEqual(expected, actual);
            }
        }
    }
}